import itemShortcuts from '../../components/shortcuts';
import inputManager from '../../scripts/inputManager';
import { playbackManager } from '../../components/playback/playbackmanager';
import imageLoader from '../../components/images/imageLoader';
import layoutManager from '../../components/layoutManager';
import browser from '../../scripts/browser';
import dom from '../../scripts/dom';
import loading from '../../components/loading/loading';
import focusManager from '../../components/focusManager';
import serverNotifications from '../../scripts/serverNotifications';
import { Events } from 'jellyfin-apiclient';
import 'webcomponents.js/webcomponents-lite';
import ServerConnections from '../../components/ServerConnections';
import Sortable from 'sortablejs';

/* eslint-disable indent */

    const ItemsContainerPrototype = Object.create(HTMLDivElement.prototype);

    function onClick(e) {
        const itemsContainer = this;
        const multiSelect = itemsContainer.multiSelect;

        if (multiSelect) {
            if (multiSelect.onContainerClick.call(itemsContainer, e) === false) {
                return;
            }
        }

        itemShortcuts.onClick.call(itemsContainer, e);
    }

    function disableEvent(e) {
        e.preventDefault();
        e.stopPropagation();
        return false;
    }

    function onContextMenu(e) {
        const target = e.target;
        const card = dom.parentWithAttribute(target, 'data-id');

        // check for serverId, it won't be present on selectserver
        if (card && card.getAttribute('data-serverid')) {
            inputManager.handleCommand('menu', {
                sourceElement: card
            });

            e.preventDefault();
            e.stopPropagation();
            return false;
        }
    }

    function getShortcutOptions() {
        return {
            click: false
        };
    }

    ItemsContainerPrototype.enableMultiSelect = function (enabled) {
        const current = this.multiSelect;

        if (!enabled) {
            if (current) {
                current.destroy();
                this.multiSelect = null;
            }
            return;
        }

        if (current) {
            return;
        }

        const self = this;
        import('../../components/multiSelect/multiSelect').then(({default: MultiSelect}) => {
            self.multiSelect = new MultiSelect({
                container: self,
                bindOnClick: false
            });
        });
    };

    function onDrop(evt, itemsContainer) {
        const el = evt.item;

        const newIndex = evt.newIndex;
        const itemId = el.getAttribute('data-playlistitemid');
        const playlistId = el.getAttribute('data-playlistid');

        if (!playlistId) {
            const oldIndex = evt.oldIndex;
            el.dispatchEvent(new CustomEvent('itemdrop', {
                detail: {
                    oldIndex: oldIndex,
                    newIndex: newIndex,
                    playlistItemId: itemId
                },
                bubbles: true,
                cancelable: false
            }));
            return;
        }

        const serverId = el.getAttribute('data-serverid');
        const apiClient = ServerConnections.getApiClient(serverId);

        loading.show();

        apiClient.ajax({
            url: apiClient.getUrl('Playlists/' + playlistId + '/Items/' + itemId + '/Move/' + newIndex),
            type: 'POST'
        }).then(function () {
            loading.hide();
        }, function () {
            loading.hide();
            itemsContainer.refreshItems();
        });
    }

    ItemsContainerPrototype.enableDragReordering = function (enabled) {
        const current = this.sortable;
        if (!enabled) {
            if (current) {
                current.destroy();
                this.sortable = null;
            }
            return;
        }

        if (current) {
            return;
        }

        const self = this;
        self.sortable = new Sortable(self, {
            draggable: '.listItem',
            handle: '.listViewDragHandle',

            // dragging ended
            onEnd: function (evt) {
                return onDrop(evt, self);
            }
        });
    };

    function onUserDataChanged(e, apiClient, userData) {
        const itemsContainer = this;

        import('../../components/cardbuilder/cardBuilder').then((cardBuilder) => {
            cardBuilder.onUserDataChanged(userData, itemsContainer);
        });

        const eventsToMonitor = getEventsToMonitor(itemsContainer);

        // TODO: Check user data change reason?
        if (eventsToMonitor.indexOf('markfavorite') !== -1) {
            itemsContainer.notifyRefreshNeeded();
        } else if (eventsToMonitor.indexOf('markplayed') !== -1) {
            itemsContainer.notifyRefreshNeeded();
        }
    }

    function getEventsToMonitor(itemsContainer) {
        const monitor = itemsContainer.getAttribute('data-monitor');
        if (monitor) {
            return monitor.split(',');
        }

        return [];
    }

    function onTimerCreated(e, apiClient, data) {
        const itemsContainer = this;

        if (getEventsToMonitor(itemsContainer).indexOf('timers') !== -1) {
            itemsContainer.notifyRefreshNeeded();
            return;
        }

        const programId = data.ProgramId;
        // This could be null, not supported by all tv providers
        const newTimerId = data.Id;

        import('../../components/cardbuilder/cardBuilder').then((cardBuilder) => {
            cardBuilder.onTimerCreated(programId, newTimerId, itemsContainer);
        });
    }

    function onSeriesTimerCreated() {
        const itemsContainer = this;
        if (getEventsToMonitor(itemsContainer).indexOf('seriestimers') !== -1) {
            itemsContainer.notifyRefreshNeeded();
            return;
        }
    }

    function onTimerCancelled(e, apiClient, data) {
        const itemsContainer = this;
        if (getEventsToMonitor(itemsContainer).indexOf('timers') !== -1) {
            itemsContainer.notifyRefreshNeeded();
            return;
        }

        import('../../components/cardbuilder/cardBuilder').then((cardBuilder) => {
            cardBuilder.onTimerCancelled(data.Id, itemsContainer);
        });
    }

    function onSeriesTimerCancelled(e, apiClient, data) {
        const itemsContainer = this;
        if (getEventsToMonitor(itemsContainer).indexOf('seriestimers') !== -1) {
            itemsContainer.notifyRefreshNeeded();
            return;
        }

        import('../../components/cardbuilder/cardBuilder').then((cardBuilder) => {
            cardBuilder.onSeriesTimerCancelled(data.Id, itemsContainer);
        });
    }

    function onLibraryChanged(e, apiClient, data) {
        const itemsContainer = this;

        const eventsToMonitor = getEventsToMonitor(itemsContainer);
        if (eventsToMonitor.indexOf('seriestimers') !== -1 || eventsToMonitor.indexOf('timers') !== -1) {
            // yes this is an assumption
            return;
        }

        const itemsAdded = data.ItemsAdded || [];
        const itemsRemoved = data.ItemsRemoved || [];
        if (!itemsAdded.length && !itemsRemoved.length) {
            return;
        }

        const parentId = itemsContainer.getAttribute('data-parentid');
        if (parentId) {
            const foldersAddedTo = data.FoldersAddedTo || [];
            const foldersRemovedFrom = data.FoldersRemovedFrom || [];
            const collectionFolders = data.CollectionFolders || [];

            if (foldersAddedTo.indexOf(parentId) === -1 && foldersRemovedFrom.indexOf(parentId) === -1 && collectionFolders.indexOf(parentId) === -1) {
                return;
            }
        }

        itemsContainer.notifyRefreshNeeded();
    }

    function onPlaybackStopped(e, stopInfo) {
        const itemsContainer = this;
        const state = stopInfo.state;

        const eventsToMonitor = getEventsToMonitor(itemsContainer);
        if (state.NowPlayingItem && state.NowPlayingItem.MediaType === 'Video') {
            if (eventsToMonitor.indexOf('videoplayback') !== -1) {
                itemsContainer.notifyRefreshNeeded(true);
                return;
            }
        } else if (state.NowPlayingItem && state.NowPlayingItem.MediaType === 'Audio') {
            if (eventsToMonitor.indexOf('audioplayback') !== -1) {
                itemsContainer.notifyRefreshNeeded(true);
                return;
            }
        }
    }

    function addNotificationEvent(instance, name, handler, owner) {
        const localHandler = handler.bind(instance);
        owner = owner || serverNotifications;
        Events.on(owner, name, localHandler);
        instance['event_' + name] = localHandler;
    }

    function removeNotificationEvent(instance, name, owner) {
        const handler = instance['event_' + name];
        if (handler) {
            owner = owner || serverNotifications;
            Events.off(owner, name, handler);
            instance['event_' + name] = null;
        }
    }

    ItemsContainerPrototype.createdCallback = function () {
        this.classList.add('itemsContainer');
    };

    ItemsContainerPrototype.attachedCallback = function () {
        this.addEventListener('click', onClick);

        if (browser.touch) {
            this.addEventListener('contextmenu', disableEvent);
        } else {
            if (this.getAttribute('data-contextmenu') !== 'false') {
                this.addEventListener('contextmenu', onContextMenu);
            }
        }

        if (layoutManager.desktop || layoutManager.mobile) {
            if (this.getAttribute('data-multiselect') !== 'false') {
                this.enableMultiSelect(true);
            }
        }

        if (layoutManager.tv) {
            this.classList.add('itemsContainer-tv');
        }

        itemShortcuts.on(this, getShortcutOptions());

        addNotificationEvent(this, 'UserDataChanged', onUserDataChanged);
        addNotificationEvent(this, 'TimerCreated', onTimerCreated);
        addNotificationEvent(this, 'SeriesTimerCreated', onSeriesTimerCreated);
        addNotificationEvent(this, 'TimerCancelled', onTimerCancelled);
        addNotificationEvent(this, 'SeriesTimerCancelled', onSeriesTimerCancelled);
        addNotificationEvent(this, 'LibraryChanged', onLibraryChanged);
        addNotificationEvent(this, 'playbackstop', onPlaybackStopped, playbackManager);

        if (this.getAttribute('data-dragreorder') === 'true') {
            this.enableDragReordering(true);
        }
    };

    ItemsContainerPrototype.detachedCallback = function () {
        clearRefreshInterval(this);

        this.enableMultiSelect(false);
        this.enableDragReordering(false);
        this.removeEventListener('click', onClick);
        this.removeEventListener('contextmenu', onContextMenu);
        this.removeEventListener('contextmenu', disableEvent);

        itemShortcuts.off(this, getShortcutOptions());

        removeNotificationEvent(this, 'UserDataChanged');
        removeNotificationEvent(this, 'TimerCreated');
        removeNotificationEvent(this, 'SeriesTimerCreated');
        removeNotificationEvent(this, 'TimerCancelled');
        removeNotificationEvent(this, 'SeriesTimerCancelled');
        removeNotificationEvent(this, 'LibraryChanged');
        removeNotificationEvent(this, 'playbackstop', playbackManager);

        this.fetchData = null;
        this.getItemsHtml = null;
        this.parentContainer = null;
    };

    ItemsContainerPrototype.pause = function () {
        clearRefreshInterval(this, true);
        this.paused = true;
    };

    ItemsContainerPrototype.resume = function (options) {
        this.paused = false;

        const refreshIntervalEndTime = this.refreshIntervalEndTime;
        if (refreshIntervalEndTime) {
            const remainingMs = refreshIntervalEndTime - new Date().getTime();
            if (remainingMs > 0 && !this.needsRefresh) {
                resetRefreshInterval(this, remainingMs);
            } else {
                this.needsRefresh = true;
                this.refreshIntervalEndTime = null;
            }
        }

        if (this.needsRefresh || (options && options.refresh)) {
            return this.refreshItems();
        }

        return Promise.resolve();
    };

    ItemsContainerPrototype.refreshItems = function () {
        if (!this.fetchData) {
            return Promise.resolve();
        }

        if (this.paused) {
            this.needsRefresh = true;
            return Promise.resolve();
        }

        this.needsRefresh = false;

        return this.fetchData().then(onDataFetched.bind(this));
    };

    ItemsContainerPrototype.notifyRefreshNeeded = function (isInForeground) {
        if (this.paused) {
            this.needsRefresh = true;
            return;
        }

        const timeout = this.refreshTimeout;
        if (timeout) {
            clearTimeout(timeout);
        }

        if (isInForeground === true) {
            this.refreshItems();
        } else {
            this.refreshTimeout = setTimeout(this.refreshItems.bind(this), 10000);
        }
    };

    function clearRefreshInterval(itemsContainer, isPausing) {
        if (itemsContainer.refreshInterval) {
            clearInterval(itemsContainer.refreshInterval);
            itemsContainer.refreshInterval = null;

            if (!isPausing) {
                itemsContainer.refreshIntervalEndTime = null;
            }
        }
    }

    function resetRefreshInterval(itemsContainer, intervalMs) {
        clearRefreshInterval(itemsContainer);

        if (!intervalMs) {
            intervalMs = parseInt(itemsContainer.getAttribute('data-refreshinterval') || '0');
        }

        if (intervalMs) {
            itemsContainer.refreshInterval = setInterval(itemsContainer.notifyRefreshNeeded.bind(itemsContainer), intervalMs);
            itemsContainer.refreshIntervalEndTime = new Date().getTime() + intervalMs;
        }
    }

    function onDataFetched(result) {
        const items = result.Items || result;

        const parentContainer = this.parentContainer;
        if (parentContainer) {
            if (items.length) {
                parentContainer.classList.remove('hide');
            } else {
                parentContainer.classList.add('hide');
            }
        }

        const activeElement = document.activeElement;
        let focusId;
        let hasActiveElement;

        if (this.contains(activeElement)) {
            hasActiveElement = true;
            focusId = activeElement.getAttribute('data-id');
        }

        this.innerHTML = this.getItemsHtml(items);

        imageLoader.lazyChildren(this);

        if (hasActiveElement) {
            setFocus(this, focusId);
        }

        resetRefreshInterval(this);

        if (this.afterRefresh) {
            this.afterRefresh(result);
        }
    }

    function setFocus(itemsContainer, focusId) {
        if (focusId) {
            const newElement = itemsContainer.querySelector('[data-id="' + focusId + '"]');
            if (newElement) {
                try {
                    focusManager.focus(newElement);
                    return;
                } catch (err) {
                    console.error(err);
                }
            }
        }

        focusManager.autoFocus(itemsContainer);
    }

    document.registerElement('emby-itemscontainer', {
        prototype: ItemsContainerPrototype,
        extends: 'div'
    });

/* eslint-enable indent */
